package com.sunlee.admin.api.module.job.template.impl;

import com.sunlee.admin.api.module.job.dto.CrawlerResourceTaskDTO;
import com.sunlee.admin.api.module.job.template.CrawResourceTemplate;
import com.sunlee.admin.api.util.FileUtil;
import com.sunlee.admin.api.util.JsoupUtil;
import com.sunlee.admin.api.module.job.template.context.CrawResourceContext;
import com.sunlee.common.core.utils.StringUtil;
import com.sunlee.common.core.exception.BusinessException;
import com.sunlee.common.service.entity.ThirdProductEntity;
import com.sunlee.common.service.enums.ThirdResStatusEnum;
import com.sunlee.common.service.service.ThirdCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CrawResourceFirstPpt extends CrawResourceTemplate {

    /**
     * 第一PPT域名
     */
    private final static String FIRST_PPT_DOMAIN = "https://www.1ppt.com/";
    private final static String FIRST_PPT_PAGE_URL = FIRST_PPT_DOMAIN + "{0}/{1}";

    /**
     * 资源下载页地址
     */
    private final static String DOWNLOAD_URL_FORMAT = "https://www.1ppt.com/plus/download.php?aid={0}";


    private final static String PUBLIC_KEY = "3000176000856006061501533003690027800375";

    private final static HashMap<String, String> COOKIE = new HashMap<>(4);

    private final static Pattern PATTERN_ARG1 = Pattern.compile("var arg1='([^']*)';");

    private final static Map<Object, Object> HEADERS = new HashMap<>(4);

    /**
     * 资源详情页地址
     */
    private final static String DETAIL_URL_FORMAT = "https://www.1ppt.com/article/{0}.html";

    @Autowired
    private ThirdCategoryService thirdCategoryService;

    @Override
    protected void collectThirdResIds(CrawResourceContext context) {

        Document document = requestGet(context.getCurUrl());

        Elements tpList = document.getElementsByClass("tplist");

        List<String> resUrls = tpList.select("li").select("h2").select("a").eachAttr("href");

        if (CollectionUtils.isEmpty(resUrls)) {
            throw new BusinessException("获取ZipUrl异常");
        }

        // 获取第三方资源id
        List<String> thirdResIds = resUrls.stream().map(item ->
                item.replace("/article/", "")
                        .replace(".html", ""))
                .collect(Collectors.toList());

        context.setThirdResIdList(thirdResIds);

        if (CollectionUtils.isEmpty(thirdResIds)) {
            context.setSkipProcess(true);
        }
    }

    /**
     * 构建下载链接
     * 根据第三方ID，获取zip网络地址
     *
     * @param context 上下文
     */
    @Override
    protected void collectDownloadUrls(CrawResourceContext context) {
        List<String> thirdResIdList = context.getThirdResIdList();
        Map<String, String> downloadUrlMap = new HashMap<>(thirdResIdList.size());
        context.setDownloadUrlMap(downloadUrlMap);

        List<String> errorThirdIds = new ArrayList<>();

        for (String thirdResId : thirdResIdList) {
            String requestUrl = MessageFormat.format(DOWNLOAD_URL_FORMAT, thirdResId);
            Document downloadDocument;
            try {
                // 第一次空头请求
                String firstGetHtml = requestGet(requestUrl).html();
                String arg1 = regGetArg1(firstGetHtml);
                if (StringUtils.isBlank(arg1)) {
                    throw new BusinessException("反爬虫规则变更！！！");
                }

                // 处理二次请求前加密
                String boxStr = unsBox(arg1);
                String acwScV2 = hexXor(boxStr, PUBLIC_KEY);
                COOKIE.put("acw_sc__v2", acwScV2);

                // 防止重定向
                HEADERS.put("Referer", MessageFormat.format(DETAIL_URL_FORMAT, thirdResId));
                downloadDocument = JsoupUtil.getDocument(requestUrl, 0, COOKIE, HEADERS).get();
            } catch (IOException e) {
                log.error("crawlerResourceTask-request-download-io-error：{}", requestUrl, e);
                throw new BusinessException("网络请求异常");
            }

            String downloadUrl = downloadDocument.getElementsByClass("downloadlist").select("a").get(0).attr("href");
            if (!downloadUrl.endsWith(".zip") && !downloadUrl.endsWith(".rar")) {
                log.error("非压缩包：tid={},url={}", thirdResId, downloadUrl);
                errorThirdIds.add(thirdResId);
                continue;
            }
            downloadUrlMap.put(thirdResId, downloadUrl);
        }

        if (errorThirdIds.size() > 0) {
            thirdResIdList.removeAll(errorThirdIds);
            log.info("移除没有非压缩包的ID：tids={}", errorThirdIds);
        }

        if (CollectionUtils.isEmpty(thirdResIdList)) {
            context.setSkipProcess(true);
        }
    }

    /**
     * 初始化：构建资源地址（处理下载方式、分页场景、地址填充等）
     *
     * @param context 上下文
     */
    @Override
    protected void initLoop(CrawResourceContext context) {
        convertUrlList(context);
        super.initLoop(context);
    }

    /**
     * 请求第三方详情页，获取基本信息：标题、标签、内容
     */
    @Override
    protected void buildEntityList(CrawResourceContext context) {

        CrawlerResourceTaskDTO dto = context.getDto();
        Map<String, String> downloadUrlMap = context.getDownloadUrlMap();

        List<ThirdProductEntity> entityList = new ArrayList<>();
        context.setThirdProductEntityList(entityList);

        for (String thirdResId : context.getThirdResIdList()) {
            // 请求
            Document document = requestGet(MessageFormat.format(DETAIL_URL_FORMAT, thirdResId));

            // 封装
            ThirdProductEntity entity = new ThirdProductEntity();

            // 第三方ID
            entity.setThirdResId(thirdResId);
            // 来源
            entity.setSource(dto.getSource());
            // 状态
            entity.setStatus(ThirdResStatusEnum.OBTAIN_ZIP.getCode());
            // 下载路径
            String downloadUrl = downloadUrlMap.get(thirdResId);
            entity.setSourceDownloadUrl(downloadUrl);
            // 压缩包路径
            entity.setZipPath(FileUtil.appendSeparator(dto.getTargetFolder()) + thirdResId + FileUtil.getTypePartDot(downloadUrl));

            // 标题
            String title = document.getElementsByClass("ppt_info clearfix")
                    .select("h1").text()
                    .replace("PPT", "")
                    .replace("模板", "")
                    .replace("免费", "")
                    .replace("下载", "");
            entity.setTitle(FileUtil.fileNameCheck(title));

            // 标签
            Elements infoLeft = document.getElementsByClass("info_left").select("li");
            for (Element element : infoLeft) {
                if (element.text().contains("标签")) {
                    entity.setTag(String.join("/", element.select("a").eachText()));
                }
            }

            // 内容
            Elements contentElements = document.getElementsByClass("content");
            List<String> contentList = contentElements.select("p").eachText();
            entity.setContent(StringUtil.subString(String.join("", contentList), 0, 2000));

            // 收集记录
            entityList.add(entity);
        }

    }

    /**
     * 请求第三方网站，获取document
     *
     * @param url 请求地址
     */
    protected Document requestGet(String url) {
        try {
            Document document = JsoupUtil.connectByGet(url);
            if (Objects.isNull(document)) {
                throw new BusinessException("返回数据异常");
            }
            return document;
        } catch (Exception e) {
            log.error("第三方资源爬取异常：{}", url, e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 构建具体的资源下载地址
     *
     * @param context 上下文
     */
    private void convertUrlList(CrawResourceContext context) {
        List<String> urlList = new ArrayList<>();
        context.setUrlList(urlList);

        // 首次请求获取分页信息
        Document document = requestGet(FIRST_PPT_DOMAIN + context.getCurThirdCategory());
        Elements pageList = document.getElementsByClass("pages").select("li");

        // 无分页，只取第一页
        if (pageList.size() == 1) {
            urlList.add(FIRST_PPT_DOMAIN + context.getCurThirdCategory());
            return;
        }
        String hrefUrl = pageList.select("a").last().attr("href");
        String endPageNum;
        // 有不同的取数规则
        if (hrefUrl.contains("_")) {
            endPageNum = StringUtil.subLastCharCentre(hrefUrl, "_", ".");
        } else {
            endPageNum = StringUtil.getNumeric(hrefUrl);
        }

        int endPageNumInt = Integer.parseInt(endPageNum);
        CrawlerResourceTaskDTO dto = context.getDto();

        // 爬取的起始页（不设置默认第一页开始）
        int startPage = (Objects.isNull(dto.getStartPage()) || dto.getStartPage() < 0) ? 1 : dto.getStartPage();
        // 爬取的结束页（不设置默认最后一页结束)
        int endPage = (Objects.isNull(dto.getEndPage()) || dto.getEndPage() < 0) ? endPageNumInt : Math.min(endPageNumInt, dto.getEndPage());

        for (int curPage = startPage; curPage <= endPage; curPage++) {
            urlList.add(MessageFormat.format(FIRST_PPT_PAGE_URL, context.getCurThirdCategory(), hrefUrl.replace(endPageNum, String.valueOf(curPage))));
        }
    }

    public static String regGetArg1(String html) {
        Matcher m3 = PATTERN_ARG1.matcher(html);
        if (m3.find()) {
            return m3.group(1);
        }
        return null;
    }

    private static String unsBox(String arg1) {
        int[] _0x4b082b = new int[]{0xf, 0x23, 0x1d, 0x18, 0x21, 0x10, 0x1, 0x26, 0xa, 0x9, 0x13, 0x1f, 0x28, 0x1b, 0x16, 0x17, 0x19, 0xd, 0x6, 0xb, 0x27, 0x12, 0x14, 0x8, 0xe, 0x15, 0x20, 0x1a, 0x2, 0x1e, 0x7, 0x4, 0x11, 0x5, 0x3, 0x1c, 0x22, 0x25, 0xc, 0x24};
        char[] _0x4da0dc = new char[arg1.length()];
        String _0x12605e = "";
        for (int _0x20a7bf = 0; _0x20a7bf < arg1.length(); _0x20a7bf++) {
            char _0x385ee3 = arg1.charAt(_0x20a7bf);
            for (int _0x217721 = 0; _0x217721 < _0x4b082b.length; _0x217721++) {
                if (_0x4b082b[_0x217721] == _0x20a7bf + 1) {
                    _0x4da0dc[_0x217721] = _0x385ee3;
                }
            }
        }
        for (char c : _0x4da0dc) {
            _0x12605e += String.valueOf(c);
        }
        return _0x12605e;
    }

    private static String hexXor(String s1, String _0x4e08d8) {
        String _0x5a5d3b = "";
        for (int _0xe89588 = 0; _0xe89588 < s1.length() && _0xe89588 < _0x4e08d8.length(); _0xe89588 += 2) {
            int _0x401af1 = Integer.parseInt(s1.substring(_0xe89588, _0xe89588 + 2), 16);
            int _0x105f59 = Integer.parseInt(_0x4e08d8.substring(_0xe89588, _0xe89588 + 2), 16);
            int _0x189e2c_10 = _0x401af1 ^ _0x105f59;
            String _0x189e2c = Integer.toHexString(_0x189e2c_10);
            if (_0x189e2c.length() == 1) {
                _0x189e2c = '0' + _0x189e2c;
            }
            _0x5a5d3b += _0x189e2c;
        }
        return _0x5a5d3b;
    }
}
